
#include "RobboLito.h"
#include "RobboTripleBase.h"
#include <string.h>
#include "RobboTotalBase.h"


RobboTripleBase* TABLE_TRIPLE_BASES;
int NUM_TRIPLE_BASES = 0;
uint64 START_CLOCK;

int TRIPLE_BASE_TABLE[16][16][16][16];

void un_windows_triple (char *A)
{
  int s = strlen (A);
  if (A[1] == 'w')
    A[0] = A[2] - 32;
  if (A[1] == 'b')
    A[0] = A[2];
  if (s > 3 && A[3] == 'w')
    A[1] = A[4] - 32;
  if (s > 3 && A[3] == 'b')
    A[1] = A[4];
  if (s > 5 && A[5] == 'w')
    A[2] = A[6] - 32;
  if (s > 5 && A[5] == 'b')
    A[2] = A[6];
  A[s >> 1] = 0;
}

RobboTripleBase* cog_triple (char* I)
{
  int v, p[4] = { 0, 0, 0, 0 }, i;
  if (I[0] >= '0' && I[0] <= '9')
    return TABLE_TRIPLE_BASES + atoi (I);
  for (i = 0; i < 4 && i < strlen (I); i++)
    {
      switch (I[i])
	{
	case 'Q':
	  p[i] = wEnumQ;
	  break;
	case 'q':
	  p[i] = bEnumQ;
	  break;
	case 'R':
	  p[i] = wEnumR;
	  break;
	case 'r':
	  p[i] = bEnumR;
	  break;
	case 'B':
	  p[i] = wEnumB;
	  break;
	case 'b':
	  p[i] = bEnumB;
	  break;
	case 'N':
	  p[i] = wEnumN;
	  break;
	case 'n':
	  p[i] = bEnumN;
	  break;
	case 'P':
	  p[i] = wEnumP;
	  break;
	case 'p':
	  p[i] = bEnumP;
	  break;
	case 'Z':
	  p[i] = BlockedPawn;
	  break;
	}
    }
  v = TRIPLE_BASE_TABLE[p[0]][p[1]][p[2]][p[3]];
  if (v == -1)
    return 0;
  return TABLE_TRIPLE_BASES + (v % 65536);
}

#define SAFER_FREE(x) if ((x)) free ((x))
uint64 bytesTRIPLE, indTRIPLE, indTRIPLEx;
void CleanupTriple ()
{
  int i, j, k, l;
  for (i = 0; i < NUM_TRIPLE_BASES; i++)
    {
      SAFER_FREE ((TABLE_TRIPLE_BASES + i)->ind);
      SAFER_FREE ((TABLE_TRIPLE_BASES + i)->data);
    }
  for (i = 0; i < 16; i++)
    for (j = 0; j < 16; j++)
      for (k = 0; k < 16; k++)
        for (l = 0; l < 16; l++)
          TRIPLE_BASE_TABLE[i][j][k][l] = -1;
  NUM_TRIPLE_BASES = 0;
  bytesTRIPLE = indTRIPLE = indTRIPLEx = 0;
}

void INIT_TRIPLE_BASE ()
{
  int i, j, k, l;
  for (i = 0; i < 16; i++)
    for (j = 0; j < 16; j++)
      for (k = 0; k < 16; k++)
	for (l = 0; l < 16; l++)
	  TRIPLE_BASE_TABLE[i][j][k][l] = -1;
  TABLE_TRIPLE_BASES = malloc (TRIPLE_MAX * sizeof (RobboTripleBase));
}

void robbo_triple_utilita (RobboTripleBase * triple, char *iNOME)
{
  int i, p[4];
  char NOME[256];
  strcpy(NOME, iNOME);
  if (NOME[0] == 'K' || NOME[0]=='k')
    un_windows_triple (NOME);
  strcpy (triple->nome, NOME);
  for (i = 0; NOME[i]; i++);
  for ( ; i < 4; i++)
    NOME[i] = 0;    
  for (i = 0; i < 4; i++)
    {
      switch (NOME[i])
	{
	case 'Q':
	  p[i] = wEnumQ;
	  break;
	case 'q':
	  p[i] = bEnumQ;
	  break;
	case 'R':
	  p[i] = wEnumR;
	  break;
	case 'r':
	  p[i] = bEnumR;
	  break;
	case 'B':
	  p[i] = wEnumB;
	  break;
	case 'b':
	  p[i] = bEnumB;
	  break;
	case 'N':
	  p[i] = wEnumN;
	  break;
	case 'n':
	  p[i] = bEnumN;
	  break;
	case 'P':
	  p[i] = wEnumP;
	  break;
	case 'p':
	  p[i] = bEnumP;
	  break;
	case 'Z':
	  p[i] = BlockedPawn;
	  break;
	default:
	  p[i] = 0;
	}
      if (p[i])
	{
	  if (p[i] == wEnumP || p[i] == bEnumP)
	    triple->m[i] = 48;
	  else if (p[i] == BlockedPawn)
	    triple->m[i] = 40;
	  else
	    triple->m[i] = 64;
	}
      else
	triple->m[i] = 1;
      triple->p[i] = p[i];
    }
  if (p[0] == p[1] && p[1])
    {
      if (p[0] == p[2] && p[0] == p[1] && p[2])
	{
	  triple->m[0] =
	    (triple->m[0] * (triple->m[0] - 1) * (triple->m[0] - 2)) / 6;
	  triple->m[1] = triple->m[2] = 1;
	}
      else
	{
	  triple->m[0] = (triple->m[0] * (triple->m[0] - 1)) / 2;
	  triple->m[1] = 1;
	}
    }
  else if (p[1] == p[2] && p[2])
    {
      triple->m[1] = (triple->m[1] * (triple->m[1] - 1)) / 2;
      triple->m[2] = 1;
    }
  TRIPLE_BASE_TABLE[p[0]][p[1]][p[2]][p[3]] =
    NUM_TRIPLE_BASES + (0 << 16) + (1 << 18) + (2 << 20) + (3 << 22);
  TRIPLE_BASE_TABLE[p[1]][p[0]][p[2]][p[3]] =
    NUM_TRIPLE_BASES + (1 << 16) + (0 << 18) + (2 << 20) + (3 << 22);
  TRIPLE_BASE_TABLE[p[0]][p[2]][p[1]][p[3]] =
    NUM_TRIPLE_BASES + (0 << 16) + (2 << 18) + (1 << 20) + (3 << 22);
  TRIPLE_BASE_TABLE[p[1]][p[2]][p[0]][p[3]] =
    NUM_TRIPLE_BASES + (2 << 16) + (0 << 18) + (1 << 20) + (3 << 22);
  TRIPLE_BASE_TABLE[p[2]][p[0]][p[1]][p[3]] =
    NUM_TRIPLE_BASES + (1 << 16) + (2 << 18) + (0 << 20) + (3 << 22);
  TRIPLE_BASE_TABLE[p[2]][p[1]][p[0]][p[3]] =
    NUM_TRIPLE_BASES + (2 << 16) + (1 << 18) + (0 << 20) + (3 << 22);
}
